
#include "pongfrenzy.hpp"
#include "../score/score.hpp"

PongFrenzy::PongFrenzy() {

}

PongFrenzy::~PongFrenzy() {

}

void PongFrenzy::init(Engine *engine) {
	ground.SetImage(engine->getImage("data/pongfrenzy/ground-800.png"));
	background.SetImage(engine->getImage("data/pongfrenzy/background-800.png"));

    for(std::map<int, Player>::iterator iPlayer = engine->players.begin(); iPlayer != engine->players.end(); iPlayer++) {
		sf::Sprite racquet;
		racquet.SetImage(engine->getImage("data/pongfrenzy/racquet.png"));
		racquet.SetColor((*iPlayer).second.color);
		racquet.SetCenter(sf::Vector2f(racquet.GetImage()->GetWidth() / 2.f, racquet.GetImage()->GetHeight() / 2.f));
		racquet.SetPosition(sf::Vector2f(100 + 100,300));

		switch ((*iPlayer).first) {
		    case 0:
                racquet.Rotate(90);
                racquet.SetPosition(sf::Vector2f(600 - 12, 300));
                break;
		    case 1:
                racquet.SetPosition(sf::Vector2f(300, 12));
                break;
		    case 2:
                racquet.SetPosition(sf::Vector2f(300, 600 - 12));
                break;
		    case 3:
                racquet.Rotate(90);
                racquet.SetPosition(sf::Vector2f(12, 300));
                break;
		    default:
                break;

		}
		pongers[(*iPlayer).first].racquet = racquet;
		pongers[(*iPlayer).first].speed = 400;
    }

    ball.sprite.SetImage(engine->getImage("data/pongfrenzy/ball.png"));
    ball.sprite.SetCenter(sf::Vector2f(ball.sprite.GetImage()->GetWidth() / 2.f, ball.sprite.GetImage()->GetHeight() / 2.f));

    gamesLeft = 4;

    gameInit(engine);
}

void PongFrenzy::gameInit(Engine *engine) {
    gamesLeft--;
    if(gamesLeft == 0) {
         engine->changeState(Score::getSingleton());
         return;
    }
    ball.sprite.SetPosition(sf::Vector2f(300,300));
    ball.speed = sf::Randomizer::Random(150,300);
    ball.direction = sf::Randomizer::Random(0.f, 2.f * PI);
    ball.owner = 4;
}

void PongFrenzy::cleanup() {
    pongers.clear();
}

void PongFrenzy::pause() {

}

void PongFrenzy::resume() {
	clock.Reset();
}

void PongFrenzy::processEvent(Engine *engine, PlayerEvent& event) {
	switch(event.type) {
		case PlayerEvent::Quit:
		{
			if(event.state)
				engine->changeState(Score::getSingleton());
			break;
		}
		default:
			break;
	}

}

void PongFrenzy::update(Engine *engine) {

	float time = clock.GetElapsedTime();
	clock.Reset();

	for(std::map<int, Ponger>::iterator iPonger = pongers.begin(); iPonger != pongers.end(); iPonger++) {
		int index = (*iPonger).first;
		Ponger& ponger = (*iPonger).second;

		if((engine->players[index].actions[PlayerEvent::MoveUp].state) && (index == 0 || index == 3))
            if(ponger.racquet.GetPosition().y <= 145.f) ponger.racquet.SetY(145.f);
                else ponger.racquet.Move(sf::Vector2f(0.f, (0 - ponger.speed) * time));
        if((engine->players[index].actions[PlayerEvent::MoveDown].state) && (index == 0 || index == 3))
            if(ponger.racquet.GetPosition().y >= 600.f - 145.f) ponger.racquet.SetY(600.f - 145.f);
                else ponger.racquet.Move(sf::Vector2f(0.f,ponger.speed * time));
		if((engine->players[index].actions[PlayerEvent::MoveLeft].state) && (index == 1 || index == 2))
            if(ponger.racquet.GetPosition().x <= 145.f) ponger.racquet.SetX(145.f);
                else ponger.racquet.Move(sf::Vector2f((0 - ponger.speed * time), 0.f));
        if((engine->players[index].actions[PlayerEvent::MoveRight].state) && (index == 1 || index == 2))
            if(ponger.racquet.GetPosition().x >= 600.f - 145.f) ponger.racquet.SetX(600.f - 145.f);
                else ponger.racquet.Move(sf::Vector2f(ponger.speed * time, 0.f));
	}
    if(isCollisionCercle(0.f, 0.f, 100.f, ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetWidth() / 2.f) == true)
        ball.direction = ball.direction + PI - 2 * (atan((ball.sprite.GetPosition().y - 0.f)/(ball.sprite.GetPosition().x - 0.f)) - ((3 * PI / 2) - ball.direction));
    if(isCollisionCercle(600.f, 0.f, 100.f, ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetWidth() / 2.f) == true)
        ball.direction = ball.direction + PI - 2 * (atan((ball.sprite.GetPosition().y - 0.f)/(ball.sprite.GetPosition().x - 600.f)) - ((3 * PI / 2) - ball.direction));
    if(isCollisionCercle(0.f, 600.f, 100.f, ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetWidth() / 2.f) == true)
        ball.direction = ball.direction + PI - 2 * (atan((ball.sprite.GetPosition().y - 600.f)/(ball.sprite.GetPosition().x - 0.f)) - ((3 * PI / 2) - ball.direction));
    if(isCollisionCercle(600.f, 600.f, 100.f, ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetWidth() / 2.f) == true)
        ball.direction = ball.direction + PI - 2 * (atan((ball.sprite.GetPosition().y - 600.f)/(ball.sprite.GetPosition().x - 600.f)) - ((3 * PI / 2) - ball.direction));

    float distance;
    for(std::map<int, Ponger>::iterator iPonger = pongers.begin(); iPonger != pongers.end(); iPonger++){
        if((*iPonger).first == 0)
            if(isCollisionRect(ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetHeight(), ball.sprite.GetImage()->GetWidth(), (*iPonger).second.racquet.GetPosition().x, (*iPonger).second.racquet.GetPosition().y, (*iPonger).second.racquet.GetImage()->GetWidth(), (*iPonger).second.racquet.GetImage()->GetHeight()) == true) {
                distance = ball.sprite.GetPosition().y - (*iPonger).second.racquet.GetPosition().y;
                ball.direction = 0 - ball.direction + distance / 40.f;
                ball.owner = 0;
            }
         if((*iPonger).first == 3)
            if(isCollisionRect(ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetHeight(), ball.sprite.GetImage()->GetWidth(), (*iPonger).second.racquet.GetPosition().x, (*iPonger).second.racquet.GetPosition().y, (*iPonger).second.racquet.GetImage()->GetWidth(), (*iPonger).second.racquet.GetImage()->GetHeight()) == true) {
                distance = ball.sprite.GetPosition().y - (*iPonger).second.racquet.GetPosition().y;
                ball.direction = 0 - ball.direction + distance / 40.f;
                ball.owner = 3;
            }
        if((*iPonger).first == 1)
            if(isCollisionRect(ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetHeight(), ball.sprite.GetImage()->GetWidth(), (*iPonger).second.racquet.GetPosition().x, (*iPonger).second.racquet.GetPosition().y, (*iPonger).second.racquet.GetImage()->GetHeight(), (*iPonger).second.racquet.GetImage()->GetWidth()) == true) {
                distance = ball.sprite.GetPosition().x - (*iPonger).second.racquet.GetPosition().x;
                ball.direction = 0 - ball.direction + PI + distance / 40.f;
                ball.owner = 1;
            }
        if((*iPonger).first == 2)
            if(isCollisionRect(ball.sprite.GetPosition().x, ball.sprite.GetPosition().y, ball.sprite.GetImage()->GetHeight(), ball.sprite.GetImage()->GetWidth(), (*iPonger).second.racquet.GetPosition().x, (*iPonger).second.racquet.GetPosition().y, (*iPonger).second.racquet.GetImage()->GetHeight(), (*iPonger).second.racquet.GetImage()->GetWidth()) == true) {
                distance = ball.sprite.GetPosition().x - (*iPonger).second.racquet.GetPosition().x;
                ball.direction = 0 - ball.direction + PI + distance / 40.f;
                ball.owner = 2;
            }
    }

    if(ball.owner != 4)ball.sprite.SetColor(engine->players[ball.owner].color);
        else ball.sprite.SetColor(sf::Color(255,255,255,255));
	ball.sprite.Move(sin(ball.direction) * ball.speed * time, cos(ball.direction) * ball.speed * time);

    if(ball.sprite.GetPosition().x < -10) {
        addScore(engine, 3 , ball.owner);
        gameInit(engine);
        return;
    }
    if(ball.sprite.GetPosition().x > 610) {
        addScore(engine, 0 , ball.owner);
        gameInit(engine);
        return;
    }
    if(ball.sprite.GetPosition().y < -10) {
        addScore(engine, 1 , ball.owner);
        gameInit(engine);
        return;
    }
    if(ball.sprite.GetPosition().y > 610) {
        addScore(engine, 2 , ball.owner);
        gameInit(engine);
        return;
    }
}

void PongFrenzy::draw(Engine *engine) {
    engine->window.Draw(ground);

	for(std::map<int, Ponger>::iterator iPonger = pongers.begin(); iPonger != pongers.end(); iPonger++)
		engine->window.Draw((*iPonger).second.racquet);

	engine->window.Draw(ball.sprite);

	engine->window.Draw(background);
}

bool PongFrenzy::isCollisionCercle(float cx1, float cy1, float cr1, float cx2, float cy2, float cr2) {

    double d = (cx1 - cx2) * (cx1 - cx2) + (cy1 - cy2) * (cy1 - cy2);
    d = sqrt(d);

    if(d <= (cr1 + cr2)) return true;
    return false;
}

bool PongFrenzy::isCollisionRect(float x1, float y1, float h1, float w1, float x2, float y2, float h2, float w2) {

    if(x1 - w1 / 2.f > x2 + w2 / 2.f) return false;
    if(x1 + w1 / 2.f < x2 - w2 / 2.f) return false;
    if(y1 + h1 / 2.f < y2 - h2 / 2.f) return false;
    if(y1 - h1 / 2.f > y2 + h2 / 2.f) return false;
    return true;
}

void PongFrenzy::addScore(Engine *engine, int loser, int winner) {
    if (winner != loser){
        if(winner != 4) {
            engine->players[winner].score += 15;
            if(engine->players[winner].score < 0) engine->players[winner].score = 0;
        }

        engine->players[loser].score -= 5;
        if(engine->players[loser].score < 0) engine->players[loser].score = 0;

    }
}
